/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.datatheorem.ohos.trustkit.pinning;

import com.datatheorem.ohos.trustkit.TrustKit;
import com.datatheorem.ohos.trustkit.config.DomainPinningPolicy;
import com.datatheorem.ohos.trustkit.config.TrustKitConfiguration;
import com.datatheorem.ohos.trustkit.reporting.BackgroundReporter;

import java.io.IOException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Set;

import javax.net.ssl.X509TrustManager;


public class TrustManagerBuilder {

    // The trust manager we will use to perform the default SSL validation
    static X509TrustManager baselineTrustManager = null;

    // Pinning validation can be disabled if debug-overrides is set
    static boolean shouldOverridePins = false;

    // The reporter that will send pinning failure reports
    static BackgroundReporter backgroundReporter = null;

    public static void initializeBaselineTrustManager(Set<Certificate> debugCaCerts,
                                                      boolean debugOverridePins,
                                                      BackgroundReporter reporter)
        throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
        IOException {
        if (baselineTrustManager != null) {
            throw new IllegalStateException("TrustManagerBuilder has already been initialized");
        }
        baselineTrustManager = SystemTrustManager.getInstance();

        shouldOverridePins = debugOverridePins;
        if ((debugCaCerts != null) && (debugCaCerts.size() > 0)) {
            // Debug overrides is enabled and we are on a pre-N device; we need to do it manually
            baselineTrustManager = DebugOverridesTrustManager.getInstance(debugCaCerts);
        }
        backgroundReporter = reporter;
    }

    public static X509TrustManager getTrustManager(String serverHostname) {
        if (baselineTrustManager == null) {
            throw new IllegalStateException("TrustManagerBuilder has not been initialized");
        }
        // Get the pinning policy for this hostname
        DomainPinningPolicy serverConfig = null;

        TrustKitConfiguration configuration = TrustKit.getInstance().getConfiguration();
        if (configuration == null) {
            return baselineTrustManager;
        }
        serverConfig = configuration.getPolicyForHostname(serverHostname);
        if ((serverConfig == null) || (shouldOverridePins)) {
            // Domain is NOT pinned or there is a debug override - only do baseline validation
            return baselineTrustManager;
        } else {
            return new PinningTrustManager(serverHostname, serverConfig, baselineTrustManager);
        }
    }

    /**
     * Retrieve the background reporter to be used for sending pinning validation reports.
     *
     * @return BackgroundReporter
     * @throws IllegalStateException
     */
    static BackgroundReporter getReporter() {
        if (backgroundReporter == null) {
            throw new IllegalStateException("TrustManagerBuilder has not been initialized");
        }
        return backgroundReporter;
    }

    public static void clean() {
        if (baselineTrustManager != null) {
            baselineTrustManager = null;
        }
    }
}
